package com.juyu.miliao.api.service;

import com.alibaba.fastjson.JSONObject;
import com.juyu.miliao.api.constant.AnswerStatusRedis;
import com.juyu.miliao.api.constant.UserLineStatusConstant;
import com.juyu.miliao.api.dao.mysql.UserVideoDao;
import com.juyu.miliao.api.dao.redis.UserCallRedisDao;
import com.juyu.miliao.api.domain.UserVideo;
import com.juyu.miliao.api.util.RedisKeys;
import com.juyu.miliao.common.constant.HomeVideoTypeConstant;
import com.juyu.miliao.common.constant.PackageGroupConstant;
import com.juyu.miliao.common.constant.PageConstant;
import com.juyu.miliao.common.domain.BaseQuery;
import com.juyu.miliao.common.domain.CommonHead;
import com.juyu.miliao.common.domain.ConfigApp;
import com.juyu.miliao.common.domain.PageIndex;
import com.juyu.miliao.common.domain.dto.HomeVideoCacheKeyDTO;
import com.juyu.miliao.common.util.CommonUtil;
import com.juyu.miliao.common.util.HomeVideoUtil;
import com.juyu.miliao.common.util.PageInfoUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static com.juyu.miliao.common.constant.HomeVideoRedis.DEFAULT_GLOBAL_KEY_VALUE;

/**
 * @author jh
 * 2018/7/23
 */
@Service(value = "homeVideoService")
public class HomeVideoService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private UserVideoDao userVideoDao;

    @Resource
    private FollowService followService;

    @Resource
    private UserCallRedisDao userCallRedisDao;

    @Resource
    private ConfigAppService configAppService;

    /**
     * 首页视频
     *
     * @param currentUserId 当前用户
     * @param baseQuery     baseQuery
     * @param recommend     是否为推荐
     * @return List<UserVideo>
     */
    public List<UserVideo> listHomeVideo(Long currentUserId, BaseQuery baseQuery, Boolean recommend, CommonHead commonHead) {
        List<UserVideo> list = new ArrayList<>();
        String homeVideoType;

        ConfigApp configApp = configAppService.getConfigApp(commonHead.getAppPackageId(), commonHead.getPhoneSystem());

        //马甲包用线下
        if (configApp != null && configApp.getPackageGroup().equals(PackageGroupConstant.VEST)) {
            homeVideoType = HomeVideoTypeConstant.VEST;
        } else {
            //花蜜和黑白包用线上
            homeVideoType = HomeVideoTypeConstant.ON_LINE;
        }

        HomeVideoCacheKeyDTO dto = HomeVideoUtil.getHomeVideoCacheKeyDTO(recommend, homeVideoType);

        String globalKey = getGlobalKey(dto.getJointGlobalKey());
        String cacheKey = dto.getJointVideoKey() + globalKey;

        Long size = stringRedisTemplate.opsForZSet().zCard(cacheKey);

        PageIndex pageIndex = PageInfoUtil.getPageIndex(baseQuery, CommonUtil.null2Long(size), false);
        if (pageIndex.getOffset() == PageConstant.OUT_OF_ROWS) {
            return list;
        }

        //取缓存
        Set<String> sortSet = stringRedisTemplate.opsForZSet().range(cacheKey,
                pageIndex.getOffset(), pageIndex.getOffset() + pageIndex.getPageSize() - 1);
        if (sortSet == null || sortSet.size() == 0) {
            return list;
        }
        list = JSONObject.parseArray(sortSet.toString(), UserVideo.class);

        //更新实时信息
        setUserOperate(list, currentUserId);

        return list;
    }

    /**
     * json字符串转换
     *
     * @param video video
     */
    private static void doChangeNull(UserVideo video) {
        //转换
        video.setDescribe(CommonUtil.null2String(video.getDescribe()));
        video.setLove(CommonUtil.null2Int(video.getLove()));
        video.setCommentNum(CommonUtil.null2Int(video.getCommentNum()));
        video.setCity(CommonUtil.null2String(video.getCity()));
        video.setNickName(CommonUtil.null2String(video.getNickName()));
        video.setVideoPrice(CommonUtil.null2String(video.getVideoPrice()));
        video.setIcon(CommonUtil.null2String(video.getIcon()));
        video.setVidType(CommonUtil.null2Int(video.getVidType()));
        video.setState(CommonUtil.null2Int(video.getState()));
    }

    /**
     * 填充用户是否点赞,关注,在线
     *
     * @param list          List<UserVideo>
     * @param currentUserId 当前用户
     */
    private void setUserOperate(List<UserVideo> list, Long currentUserId) {
        List<String> userIds = new ArrayList<>();
        for (UserVideo video : list) {
            Long videoUserId = CommonUtil.null2Long(video.getUserId());
            //用户是否点赞  关注
            if (currentUserId != null && videoUserId != -1L) {
                int like = userVideoDao.findClickVideoLove(currentUserId, video.getVideoId());
                video.setUserLike(like > 0);
                video.setUserFollow("true".equals(followService.getFollowRelation(videoUserId, currentUserId)));
            } else {
                video.setUserLike(false);
                video.setUserFollow(false);
            }

            doChangeNull(video);
            userIds.add(CommonUtil.null2String(video.getUserId()));
        }

        //在线状态
        setUserLineStatus(userIds, list);

    }

    /**
     * 获取全局key
     *
     * @param cacheTypeKey key类型 GLOBAL_RECOMMEND_KEY    GLOBAL_NEWEST_KEY
     * @return String
     */
    private String getGlobalKey(String cacheTypeKey) {
        String globalKey = stringRedisTemplate.opsForValue().get(cacheTypeKey);
        return StringUtils.isEmpty(globalKey) ? String.valueOf(DEFAULT_GLOBAL_KEY_VALUE) : globalKey;
    }


    /**
     * 更新在线状态
     *
     * @param userIds    userIds
     * @param userVideos userVideos
     */
    private void setUserLineStatus(List<String> userIds, List<UserVideo> userVideos) {
        final List<String> list = userIds;
        List<Object> results = stringRedisTemplate.executePipelined(
                (RedisCallback<Boolean>) connection -> {
                    StringRedisConnection stringRedisConn = (StringRedisConnection) connection;
                    for (String userId : list) {
                        stringRedisConn.sIsMember(RedisKeys.SET_HOSTLINE.getValue(), userId);
                    }
                    return null;
                });
        if (results.size() == userVideos.size()) {
            int i = 0;
            Long userId;
            for (UserVideo video : userVideos) {
                userId = video.getUserId();
                boolean result = CommonUtil.null2Boolean(results.get(i++));
                String flag = stringRedisTemplate.opsForValue().get(AnswerStatusRedis.ANSWER_STATUS + userId);
                //如果查不到缓存就认为是可聊,因为用户刚创建 isVideo isCall 都是打开的
                if (StringUtils.isEmpty(flag)) {
                    flag = AnswerStatusRedis.ANSWER_TRUE;
                }

                if (!result) {
                    //离线
                    video.setLineStatus(UserLineStatusConstant.OUT_LINE);
                } else if (Objects.equals(flag, AnswerStatusRedis.ANSWER_FALSE)) {
                    //勿扰
                    video.setLineStatus(UserLineStatusConstant.NOT_DISTURB);
                } else if (userCallRedisDao.findHostCall(userId.toString())) {
                    //繁忙
                    video.setLineStatus(UserLineStatusConstant.BUSY);
                } else {
                    //在线
                    video.setLineStatus(UserLineStatusConstant.ON_LINE);
                }
            }
        }

    }


//    /**
//     * 取最新的视频
//     * 规则:1.sort 2.time 3.在线   +判断是否点赞
//     * 缓存里有200条
//     *
//     * @param userId    userId
//     * @param baseQuery baseQuery
//     * @return List<UserVideo>
//     */
//    public List<UserVideo> newest(Long userId, BaseQuery baseQuery) {
//        List<UserVideo> list = new ArrayList<>();
//        PageIndex pageIndex = PageInfoUtil.getPageIndex(baseQuery, HomeVideoConstant.MAX_NEWEST, false);
//        if (pageIndex.getOffset() == PageConstant.OUT_OF_ROWS) {
//            return list;
//        }
//
//        //<editor-fold desc="取缓存和数据库数据size">
//        int basePageNum = baseQuery.getPageNum();
//        int basePageSize = baseQuery.getPageSize();
//        int cacheSize = 0;
//        int dataSize = 0;
//        if (basePageNum * basePageSize <= HomeVideoConstant.MAX_NEWEST_CACHE) {
//            //全在缓存里
//            cacheSize = basePageSize;
//        } else if ((basePageNum - 1) * basePageSize + 1 > HomeVideoConstant.MAX_NEWEST_CACHE) {
//            //全在缓存外
//            dataSize = basePageSize;
//        } else {
//            //部分在缓存里
//            cacheSize = HomeVideoConstant.MAX_NEWEST_CACHE - (basePageNum - 1) * basePageSize;
//            dataSize = basePageSize - cacheSize;
//        }
//        //</editor-fold>
//
//        String globalKey = getGlobalKey(GLOBAL_NEWEST_KEY);
//
//        //取缓存
//        if (cacheSize > 0) {
//            Set<String> sortSet = stringRedisTemplate.opsForZSet().range(NEWEST_VIDEO_CACHE + globalKey,
//                    pageIndex.getOffset(), pageIndex.getOffset() + pageIndex.getPageSize() - 1);
//            if (sortSet != null && !sortSet.isEmpty()) {
//                list.addAll(JSONObject.parseArray(sortSet.toString(), UserVideo.class));
//            }
//        }
//
//        //缓存之外
//        if (dataSize > 0) {
////            list.addAll(getNewestByData(HomeVideoConstant.MAX_NEWEST_CACHE + 1, dataSize));
//            //再取剩下的
//            List<UserVideo> other;
//            Set<String> sortSet = stringRedisTemplate.opsForZSet().reverseRange(HomeVideoRedis.NEW_SORT, 0, dataSize - 1);
//            if (!CommonUtil.isEmptyCollection(sortSet)) {
//                other = getSortList(sortSet);
//                if (!CommonUtil.isEmptyCollection(other)) {
//                    list.addAll(other);
//                }
//            }
//
//        }
//
//        //排序在线
//        return sortUserVideo(list, userId);
//    }

//    /**
//     * 查询数据库获得sortSet对应的数据
//     *
//     * @param sortSet sortSet
//     * @return List<UserVideo>
//     */
//    private List<UserVideo> getSortList(Set<String> sortSet) {
//        List<UserVideo> sortList = new ArrayList<>();
//        if (sortSet != null && !sortSet.isEmpty()) {
//            Long videoId;
//            UserVideo userVideo;
//            for (String s : sortSet) {
//                videoId = CommonUtil.null2Long(s);
//                if (videoId != -1L) {
//                    userVideo = homeVideoDao.getUserVideo(videoId);
//                    if (userVideo != null) {
//                        sortList.add(userVideo);
//                    }
//                }
//            }
//        }
//        return sortList;
//    }
//
//    /**
//     * 在线的优先排序,并查出用户是否点赞
//     *
//     * @param list   需要排序的列表
//     * @param userId 用户Id
//     * @return List<UserVideo>
//     */
//    private List<UserVideo> sortUserVideo(List<UserVideo> list, Long userId) {
//        Integer size = list.size();
//        List<UserVideo> result = new ArrayList<>(size);
//
//        //查询并把在线的优先排序  手动处理信息
//        for (UserVideo video : list) {
//            //是否在线
//            Long videoUserId = CommonUtil.null2Long(video.getUserId());
//            Boolean isOnline = lineTimeRedisDao.isMember(CommonUtil.null2String(video.getUserId()));
//            if (isOnline) {
//                result.add(video);
//            }
//
//            //判断视频User信息
//            User user = userInfoDao.getUserInfoById(videoUserId);
//            doVideoVoMapper(video, user);
//            //是否繁忙
//            if (user == null) {
//                video.setLineStatus(UserLineStatusConstant.OUT_LINE);
//            } else if (isOnline) {
//                if (user.getIsCall() == 2 && user.getIsVideo() == 2) {
//                    video.setLineStatus(UserLineStatusConstant.NOT_DISTURB);
//                } else {
//                    video.setLineStatus(UserLineStatusConstant.ON_LINE);
//                }
//            } else {
//                video.setLineStatus(UserLineStatusConstant.OUT_LINE);
//            }
//
//            //用户是否点赞  关注
//            if (userId != null) {
//                int like = userVideoDao.findClickVideoLove(userId, video.getVideoId());
//                video.setUserLike(like > 0);
//                video.setUserFollow("true".equals(followService.getFollowRelation(videoUserId, userId)));
//            } else {
//                video.setUserLike(false);
//                video.setUserFollow(false);
//            }
//
//
//        }
//
//        //剩下的添加进result
//        for (UserVideo video : list) {
//            if (Objects.equals(video.getLineStatus(), UserLineStatusConstant.OUT_LINE)) {
//                result.add(video);
//            }
//        }
//
//        return result;
//    }

//    /**
//     * 从数据库中去最新的数据
//     *
//     * @param offset   offset
//     * @param pageSize pageSize
//     * @return List<UserVideo>
//     */
//    private List<UserVideo> getNewestByData(int offset, int pageSize) {
//        List<UserVideo> sortList = new ArrayList<>();
//        //取sort
//        Set<String> sortSet = stringRedisTemplate.opsForZSet().reverseRange(HomeVideoRedis.NEW_SORT, offset, offset + pageSize - 1);
//        if (sortSet != null) {
//            sortList = getSortList(sortSet);
//        }
//
//        //sort不够根据time排序
//        List<UserVideo> timeList = new ArrayList<>();
//        int sortSize = sortList.size();
//        if (sortSize < pageSize) {
//            Integer timeSize = HomeVideoConstant.MAX_NEWEST_CACHE - sortSize;
//            //多库查询
//            timeList = homeVideoDao.listNewVideo(timeSize, sortSet);
//            //内存排序 截取
//            timeList = timeList
//                    .stream()
//                    .sorted(comparing(UserVideo::getLove).reversed())
//                    .collect(toList())
//                    .subList(0, timeList.size() < timeSize ? timeList.size() : timeSize);
//        }
//
//        //合并
//        sortList.addAll(timeList);
//
//        return sortList;
//    }

    //    /**
//     * 用户视频添加vo信息
//     *
//     * @param video UserVideo
//     * @param user  user
//     */
//    private static void doVideoVoMapper(UserVideo video, User user) {
//        if (user != null) {
//            video.setCity(CommonUtil.null2String(user.getCity()));
//            video.setNickName(CommonUtil.null2String(user.getNickName()));
//            video.setVideoPrice(CommonUtil.null2String(user.getVideoPrice()));
//            video.setIcon(CommonUtil.null2String(user.getIcon()));
//        } else {
//            video.setCity("");
//            video.setNickName("");
//            video.setVideoPrice("");
//            video.setIcon("");
//        }
//
//        //转换
//        video.setDescribe(CommonUtil.null2String(video.getDescribe()));
//        video.setLove(CommonUtil.null2Int(video.getLove()));
//        video.setCommentNum(CommonUtil.null2Int(video.getCommentNum()));
//    }


}
